package com.slunk.dodgetrain;

import java.util.Timer;
import java.util.TimerTask;

import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.slunk.physics.characters.Train;
import com.slunk.utilities.EntityCategories;
import com.slunk.utilities.Movement;
import com.slunk.utilities.TrainTrack;

public class TrainYard {	
	//difficulty settings
	private int currentNumTracks = 1;

	
	private static float width_MOD = 20.0f;
	private static float speed_MOD = 0.20f;
	
	private float randomTrainWidth_MIN = 150.0f;
	private float randomTrainWidth_MAX = 250.0f;
	private float randomTrainSpeed_MIN = 0.5f;
	private float randomTrainSpeed_MAX = 2.0f;
	
	private float trainHeight = 20.0f;
	private World world;
	private Array<Train> trains;
	
	private Array<TrainTrack> unusedTracks;
	private Array<TrainTrack> usedTracks;
	private Array<Movement> possibleMovements;
	
	private float screenHeight;
	private float screenWidth;
	
	private Timer timer;
	public boolean isReadyToDepartTrain = false;
	
	public TrainYard(World world, float screenWidth, float screenHeight) {
		this.world = world;
		this.screenHeight = screenHeight;
		this.screenWidth = screenWidth;
		this.trains = new Array<Train>();
		this.unusedTracks = new Array<TrainTrack>();
		this.usedTracks = new Array<TrainTrack>();
		this.possibleMovements = new Array<Movement>();
		this.possibleMovements.add(Movement.EAST);
		this.possibleMovements.add(Movement.WEST);
		
		
		TrainTrack track1 = new TrainTrack();
		track1.inUse = false;
		track1.yPosition = this.trainHeight * 2;
		this.unusedTracks.add(track1);
		
		TrainTrack track5 = new TrainTrack();
		track5.inUse = false;
		track5.yPosition = this.trainHeight * 5;
		this.unusedTracks.add(track5);
		
		TrainTrack track2 = new TrainTrack();
		track2.inUse = false;
		track2.yPosition = this.screenHeight - this.trainHeight * 2;
		this.unusedTracks.add(track2);
		
		TrainTrack track6 = new TrainTrack();
		track6.inUse = false;
		track6.yPosition = this.screenHeight - this.trainHeight * 5;
		this.unusedTracks.add(track6);
		
		TrainTrack track3 = new TrainTrack();
		track3.inUse = false;
		track3.yPosition = this.screenHeight/2.0f + this.trainHeight * 2;
		this.unusedTracks.add(track3);
		
		TrainTrack track4 = new TrainTrack();
		track4.inUse = false;
		track4.yPosition = this.screenHeight/2.0f - this.trainHeight * 2;
		this.unusedTracks.add(track4);
		
		this.timer = new Timer();
		this.timer.scheduleAtFixedRate(new Depart(), 1000, 1000); 
	}
	
	//Timer class to randomly keep changing the movement
	class Depart extends TimerTask {
        public void run() {
        	isReadyToDepartTrain = true;
        	timer.cancel();
        }
    }
	
	
	public void resetDifficulty() {
		this.currentNumTracks = 1;
		randomTrainWidth_MIN = 150.0f;
		randomTrainWidth_MAX = 250.0f;
		randomTrainSpeed_MIN = 0.5f;
		randomTrainSpeed_MAX = 2.0f;
	}
	
	public void increaseDifficulty() {
		if(this.currentNumTracks < 4) {
			this.currentNumTracks = this.currentNumTracks + 1;
		}
		randomTrainWidth_MIN = randomTrainWidth_MIN + width_MOD;
		randomTrainWidth_MAX = randomTrainWidth_MAX + width_MOD;
		randomTrainSpeed_MIN = randomTrainSpeed_MIN + speed_MOD;
		randomTrainSpeed_MAX = randomTrainSpeed_MAX + speed_MOD;
	}
	
	public void decreaseDifficulty() {
		if (this.currentNumTracks > 1) {
			this.currentNumTracks = this.currentNumTracks - 1;
		}
		
		randomTrainWidth_MIN = randomTrainWidth_MIN - width_MOD;
		if (randomTrainWidth_MIN < 150.0f) {
			randomTrainWidth_MIN = 150.0f;
		}
		randomTrainWidth_MAX = randomTrainWidth_MAX - width_MOD;
		if (randomTrainWidth_MAX < 250.0f) {
			randomTrainWidth_MAX = 250.0f;
		}
		randomTrainSpeed_MIN = randomTrainSpeed_MIN - speed_MOD;
		if (randomTrainSpeed_MIN < 0.5f) {
			randomTrainSpeed_MIN = 0.5f;
		}
		randomTrainSpeed_MAX = randomTrainSpeed_MAX - speed_MOD;
		if (randomTrainSpeed_MAX < 2.0f) {
			randomTrainSpeed_MAX = 2.0f;
		}
		
		//System.out.println("current number of tracks = "+this.currentNumTracks);
		//System.out.println("current min speed = "+randomTrainSpeed_MIN);
		//System.out.println("current max speed = "+randomTrainSpeed_MAX);
	}
	
	public void drawTrains(SpriteBatch batch) {
		for (Train train : this.trains) {
			train.drawSprite(batch);
		}
	}
	
	public void addTrain() {
		//if (this.unusedTracks.size > 0) {
		if (this.unusedTracks.size > 0 && this.usedTracks.size < this.currentNumTracks) {
			//copy the tracks to prevent weird race conditions that may occur
			Array<TrainTrack> unusedTracksCopy = new Array<TrainTrack>(this.unusedTracks);
			
			//Get a random index
			int randomInt = MathUtils.random(0, unusedTracksCopy.size - 1);
			
			//Get a copy of the track
			TrainTrack track = this.unusedTracks.get(randomInt);
			
			//remove from the unused tracks
			this.unusedTracks.removeValue(track, true);
			
			//add to the used tracks so that no other train can use this track until the current train is done
			this.usedTracks.add(track);
	
			//random train properties
			float trainWidth = MathUtils.random(randomTrainWidth_MIN, randomTrainWidth_MAX);
			float trainSpeed = MathUtils.random(randomTrainSpeed_MIN, randomTrainSpeed_MAX);
			
			int randomIndex = MathUtils.random(0, this.possibleMovements.size-1);
			Movement randomMovement = this.possibleMovements.get(randomIndex);
			
			boolean flipTrain = false;
			float xPosition = 0.0f;
			if (randomMovement == Movement.EAST) {
				xPosition = -trainWidth;
			} else if (randomMovement == Movement.WEST){
				flipTrain = true;
				xPosition = this.screenWidth + trainWidth;
			}
			
			
			Train train = new Train(this.world, new Vector2(xPosition,track.yPosition), trainWidth, this.trainHeight, EntityCategories.TRAIN.getEntityValue(), (short)(EntityCategories.CAR.getEntityValue() | EntityCategories.PERSON.getEntityValue() | EntityCategories.TRAIN.getEntityValue()),trainSpeed,randomMovement);
			train.setSprite("data/Train.png");
			train.getSprite().setSize(trainWidth * 2, this.trainHeight * 2);
			train.getSprite().flip(flipTrain, false);
			
			train.setTrainTrack(track);
			
			this.trains.add(train);
			
			this.isReadyToDepartTrain = false;

			this.timer = new Timer();
			this.timer.scheduleAtFixedRate(new Depart(), 1000, 1000); 
		}
	}
	
	public void removeAllTrains() {
		Array<Train> copy_trains = new Array<Train>(this.trains);
		for (Train train : copy_trains) {
			this.world.destroyBody(train.getCharacterBody());
			this.removeTrain(train);
		}
	}
	
	public void removeTrain(Train train) {
		if (this.trains.contains(train, true)) {
			
			TrainTrack track = train.getTrainTrack();
			if (!this.unusedTracks.contains(track, true)) {
				TrainTrack newUnusedTrack = new TrainTrack();
				newUnusedTrack.inUse = track.inUse;
				newUnusedTrack.yPosition = track.yPosition;
				this.unusedTracks.add(newUnusedTrack);
			}
			if (this.usedTracks.contains(track, true)) {
				this.usedTracks.removeValue(track, true);
			}
			train.track = null;
			this.trains.removeValue(train, true);
		}
	}
	
	public boolean isReadyToDepartTrain() {
		return this.isReadyToDepartTrain;
	}
	
	public Array<Train> getTrains() {
		return this.trains;
	}
	
	public void updateTrainMovements() {
		for(Train train : this.trains) {
			train.updateMovement();
			if (train.getCurrentState() == Movement.EAST) {
				if (train.getCharacterPosition().x - train.getWidth() > this.screenWidth) {
					train.planForDecomission();
				}
			} else if (train.getCurrentState() == Movement.WEST) {
				if (train.getCharacterPosition().x + train.getWidth() < 0) {
					train.planForDecomission();
				}
			}
		}
	}
	
	public boolean isBodyTrain(Body body) {
		for (Train train : this.trains) {
			if (body == train.getCharacterBody()) {
				return true;
			}
		}
		return false;
	}	
}
